#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <string.h>
#include <lwip/tcpip.h>
#include <mqtt_client.h>
#include <blog.h>

#include "queue.h"

#include "wifi_task/wifi_task.h"
#include "wb2_led.h"


#define CA_CRT  "-----BEGIN CERTIFICATE-----\r\n"\
"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\r\n"\
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"\
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\r\n"\
"MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\r\n"\
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\r\n"\
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\r\n"\
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\r\n"\
"2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\r\n"\
"1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\r\n"\
"q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\r\n"\
"tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\r\n"\
"vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\r\n"\
"BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\r\n"\
"5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\r\n"\
"1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\r\n"\
"NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\r\n"\
"Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\r\n"\
"8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\r\n"\
"pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\r\n"\
"MrY=\r\n"\
"-----END CERTIFICATE-----\r\n"

extern void proc_main_entry();

#define TOPIC_ON        "/on/led/wb2"
#define TOPIC_OFF       "/off/led/wb2"
#define TOPIC_GET       "/get/led/wb2"
#define TOPIC_STATUS    "/status/led/wb2"

axk_mqtt_client_handle_t client;
QueueHandle_t mqtt_data_queue;

typedef struct _mqtt_data {
    char* data;
    char* topic;
}mqtt_data_t;

static void log_error_if_nonzero(const char* message, int error_code)
{
    if (error_code != 0) {
        blog_error("Last error %s: 0x%x", message, error_code);
    }
}

/**
 * 根据不同的tpioc处理事件
 * @param  data
 * @param  topic
 */
void resolve_led_message(const char* data, const char* topic, axk_mqtt_client_handle_t client) {

    //打开灯
    if (strcmp(topic, TOPIC_ON) == 0) {
        wb2_led_open(data);
    }
    //关闭灯
    else if (strcmp(topic, TOPIC_OFF) == 0) {
        wb2_led_close(data);
    }
    //发送灯的状态
    else if (strcmp(topic, TOPIC_GET) == 0) {
        uint8_t pin_data = wb2_led_status(data);
        char ch_data = pin_data + '0';
        int32_t msg_id = axk_mqtt_client_publish(client, TOPIC_STATUS, &ch_data, 0, 1, 0);
        printf("send id: %d\n", msg_id);
    }
    else {
        printf("未定义：%s,%s\n", topic, data);
    }
}

static axk_err_t event_cb(axk_mqtt_event_handle_t event)
{
    int32_t event_id;
    axk_mqtt_client_handle_t client = event->client;

    event_id = event->event_id;
    blog_debug("Event dispatched, event_id=%d", event_id);
    int msg_id;
    switch ((axk_mqtt_event_id_t)event_id) {
        case MQTT_EVENT_CONNECTED:
            //订阅ON事件
            msg_id = axk_mqtt_client_subscribe(client, TOPIC_ON, 0);
            blog_info("sent subscribe successful, msg_id=%d", msg_id);

            //订阅OFF事件
            msg_id = axk_mqtt_client_subscribe(client, TOPIC_OFF, 0);
            blog_info("sent subscribe successful, msg_id=%d", msg_id);

            //订阅GET事件
            msg_id = axk_mqtt_client_subscribe(client, TOPIC_GET, 0);
            blog_info("sent subscribe successful, msg_id=%d", msg_id);
            break;
        case MQTT_EVENT_DISCONNECTED:
            blog_info("MQTT_EVENT_DISCONNECTED");
            break;

        case MQTT_EVENT_SUBSCRIBED:
            blog_info("MQTT_EVENT_SUBSCRIBED, msg_id=%d,msg_topic=%s", event->msg_id, event->topic);
            blog_info("sent publish successful, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_UNSUBSCRIBED:
            blog_info("MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_PUBLISHED:
            blog_info("MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_DATA:
            blog_info("MQTT_EVENT_DATA");
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
            printf("DATA=%.*s\r\n", event->data_len, event->data);

            //event->data后面没有'\0'分割，所以需要手动处理
            char* data = pvPortMalloc(sizeof(char) * event->data_len + 1);
            char* topic = pvPortMalloc(sizeof(char) * event->topic_len + 1);
            mqtt_data_t* mqdata = (mqtt_data_t*)pvPortMalloc(sizeof(mqtt_data_t));

            mqdata->data = data;
            mqdata->topic = topic;

            //复制data和topic
            memset(data, '\0', event->data_len + 1);
            memset(topic, '\0', event->topic_len + 1);
            memcpy(data, event->data, event->data_len);
            memcpy(topic, event->topic, event->topic_len);

            //向queue中发送消息
            xQueueSend(mqtt_data_queue, mqdata, 0);

            break;
        case MQTT_EVENT_ERROR:
            blog_info("MQTT_EVENT_ERROR");
            if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
                log_error_if_nonzero("reported from axk-tls", event->error_handle->axk_tls_last_axk_err);
                log_error_if_nonzero("reported from tls stack", event->error_handle->axk_tls_stack_err);
                log_error_if_nonzero("captured as transport's socket errno", event->error_handle->axk_transport_sock_errno);
                blog_info("Last errno string (%s)", strerror(event->error_handle->axk_transport_sock_errno));
            }
            break;
        default:
            blog_info("Other event id:%d", event->event_id);
            break;
    }
    return AXK_OK;
}

void wifi_connect_call()
{
    printf("wifi connect\n");
    axk_mqtt_client_config_t mqtt_cfg = {
        .uri = "ws://broker.emqx.io:8083/mqtt",
        .event_handle = event_cb,

        //指定客户端名称
        .client_id = "axk mqtt",
        //设置服务器证书文件
        // .cert_pem = CA_CRT,
        // .cert_len = strlen(CA_CRT) + 1,
        // .username = "wb2",
        // .password = "wb2",

        //客户端证书
        // .client_cert_pem = CLIENT_CA,
        // .client_key_pem = CLIENT_KEY,


    };

    client = axk_mqtt_client_init(&mqtt_cfg);
    axk_mqtt_client_start(client);
}

/**
 * 循环队列接收mqtt数据
 * @param  argv             
 */
void mqtt_data_task(void* argv)
{
    //创建queue
    mqtt_data_queue = xQueueCreate(10, sizeof(mqtt_data_t));
    mqtt_data_t data;
    while (pdTRUE == xQueueReceive(mqtt_data_queue, &data, portMAX_DELAY))
    {
        //接收处理消息
        resolve_led_message(data.data, data.topic, client);
    }
}

void main(void)
{
    printf("mqtt start\n");

    blog_set_level_log_component(BLOG_LEVEL_WARN, "mqtt");
    blog_set_level_log_component(BLOG_LEVEL_WARN, "axk_mqtt");

    tcpip_init(NULL, NULL);

    wb2_led_init(PIN_R);
    wb2_led_init(PIN_G);
    wb2_led_init(PIN_B);

    register_connect_callback(wifi_connect_call);
    xTaskCreate(proc_main_entry, (char*)"main_entry", 1024, NULL, 15, NULL);
    xTaskCreate(mqtt_data_task, "mqtt_data", 512, NULL, 5, NULL);
}